﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StructureMap;
using AvansRS.Domain.DataInterface;
using AvansRS.Domain;
using AvansRS.Data.InsertBuilders;

namespace AvansRS.Data
{
	public class Initializer
	{
		private IList<Person> _persons;
		private IList<EventDate> _eventDates;
		private IList<Location> _location;

		public Initializer(bool createDB, bool testData)
		{
			_persons = new List<Person>();
			_eventDates = new List<EventDate>();
			_location = new List<Location>();

			SessionProvider.CreateSessionFactory(createDB);

			SetupFactory();

			if(testData)
				InsertTestData();
		}

		private void InsertTestData()
		{
			InsertAccounts();
			InsertLocations();
			InsertEvents();
			InsertRegistrations();
            InsertStudyAndAcademy();
		}

		private void InsertRegistrations()
		{
			Random rand = new Random(1);
			for(int i = 1; i <= 5; i++)
			{
				int blockIndex = 0;
				while(blockIndex == 0)
					blockIndex = rand.Next(15);
				Registration registration = new InsertRegistration()
					 .WithEntity(_persons[i].Entity)
					 .WithEventDate(_eventDates[i])
					 .WithTimeBlock(_eventDates[i].Rooster.TimeBlock[blockIndex]);
			}
		}

		private Rooster InsertRooster()
		{
			Rooster rooster = new InsertRooster()
				 .WithName("Avans")
				 .WithDescription("Standaard Avans Rooster")
				 .WithRoosterNumber(1);

			rooster.TimeBlock = InsertTimeBlocks(rooster);

			IRepository<Rooster> rep = ObjectFactory.GetInstance<IRepository<Rooster>>();
			rep.Save(rooster);

			return rooster;
		}

		private IList<TimeBlock> InsertTimeBlocks(Rooster rooster)
		{
			List<TimeBlock> blocks = new List<TimeBlock>(17);

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("8:00", "H:m", null))
								.WithEndTime(DateTime.ParseExact("8:45", "H:m", null)));

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("8:45", "H:m", null))
								.WithEndTime(DateTime.ParseExact("9:30", "H:m", null)));

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("9:35", "H:m", null))
								.WithEndTime(DateTime.ParseExact("10:20", "H:m", null)));

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("10:35", "H:m", null))
								.WithEndTime(DateTime.ParseExact("11:20", "H:m", null)));

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("11:25", "H:m", null))
								.WithEndTime(DateTime.ParseExact("12:10", "H:m", null)));

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("12:15", "H:m", null))
								.WithEndTime(DateTime.ParseExact("13:00", "H:m", null)));

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("13:00", "H:m", null))
								.WithEndTime(DateTime.ParseExact("13:45", "H:m", null)));

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("13:50", "H:m", null))
								.WithEndTime(DateTime.ParseExact("14:35", "H:m", null))
								);

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("14:40", "H:m", null))
								.WithEndTime(DateTime.ParseExact("15:25", "H:m", null))
								);

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("15:40", "H:m", null))
								.WithEndTime(DateTime.ParseExact("16:25", "H:m", null))
								);

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("16:30", "H:m", null))
								.WithEndTime(DateTime.ParseExact("17:15", "H:m", null))
								);

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("17:15", "H:m", null))
								.WithEndTime(DateTime.ParseExact("18:00", "H:m", null))
								);

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("18:00", "H:m", null))
								.WithEndTime(DateTime.ParseExact("18:45", "H:m", null))
								);

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("18:45", "H:m", null))
								.WithEndTime(DateTime.ParseExact("19:30", "H:m", null))
								);

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("19:30", "H:m", null))
								.WithEndTime(DateTime.ParseExact("20:15", "H:m", null))
								);

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("20:30", "H:m", null))
								.WithEndTime(DateTime.ParseExact("21:15", "H:m", null))
								);

			blocks.Add(new InsertTimeBlock()
								.WithStartTime(DateTime.ParseExact("21:15", "H:m", null))
								.WithEndTime(DateTime.ParseExact("22:00", "H:m", null))
								);

			return blocks;
		}

		private void InsertEvents()
		{
			Rooster rooster = InsertRooster();
			Random rand = new Random(1);

			for(int i = 1; i <= 5; i++)
			{
				IList<Entity> entities = new List<Entity>();
				entities.Add(_persons[0].Entity);

				Event eventVal = new InsertEvent()
					 .WithName("Event " + i.ToString())
					 .WithDescription("Assesment OS3")
					 .WithLocation(_location[0])
					 .WithMaxRegistrations(5)
					 .WithApplicableEntities(entities);

				int month = 0;

				int day = 0;
				while(day == 0)
					day = rand.Next(28);

				while(month == 0)
					month = rand.Next(12);

				List<EventDate> list = new List<EventDate>(2);
				list.Add(new InsertEventDate()
								 .WithAllowChanges(true)
								 .WithDate(new DateTime(2010, month, day))
								 .WithEvent(eventVal)
								 .WithForStudents(true)
								 .WithRooster(rooster));

				try
				{
					month = 0;

					day = 0;
					while(day == 0)
						day = rand.Next(28);

					while(month == 0)
						month = rand.Next(12);

					list.Add(new InsertEventDate()
									 .WithAllowChanges(true)
									 .WithDate(new DateTime(2010, month, day))
									 .WithEvent(eventVal)
									 .WithForStudents(true)
									 .WithRooster(rooster));

				}
				catch(DataException ex)
				{
				}

				eventVal.EventDates = list;

				IRepository<Event> rep = ObjectFactory.GetInstance<IRepository<Event>>();
				rep.Save(eventVal);

				foreach(EventDate eventDate in list)
				{
					_eventDates.Add(eventDate);
				}
			}
		}

		private void InsertLocations()
		{
			Location location = new InsertLocation()
			.Withdescription("Test Description")
			.Withname("Test Name");
			_location.Add(location);




		}

		private void InsertAccounts()
		{
			Account adminAccount = new InsertAccount()
				 .WithEmail("mh.holsbrink@gmail.com")
				 .WithPassword("admin")
				 .WithUserName("admin");

			Entity entity = new InsertEntity()
				 .WithInUse(true);


			Person adminPerson = new InsertPerson()
				 .WithAccount(adminAccount)
				 .WithFirstName("admin")
				 .WithNumber(200345)
				 .WithSurName("AvansRS")
				 .WithEntity(entity);

			_persons.Add(adminPerson);

			for(int i = 1; i <= 5; i++)
			{
				Entity ent = new InsertEntity()
					 .WithInUse(true);
				Account account = new InsertAccount()
				.WithEmail("email@email.com")
				.WithPassword("test1")
				.WithUserName("username" + i.ToString());

				Person person = new InsertPerson()
					 .WithAccount(account)
					 .WithFirstName("FirstName" + i.ToString())
					 .WithNumber(i * 1000)
					 .WithSurName("LastName" + i.ToString())
					 .WithEntity(ent);

				_persons.Add(person);
			}
		}

        private void InsertStudyAndAcademy()
        {
            Study study = new InsertStudy()
            .Withname("TI");
            Study study2 = new InsertStudy()
            .Withname("I");
            Study study3 = new InsertStudy()
            .Withname("BIS");
            Study study4 = new InsertStudy()
            .Withname("WTB");

            IList<Study> l1 = new List<Study>();
            IList<Study> l2 = new List<Study>();
            l1.Add(study);
            l1.Add(study2);
            l1.Add(study3);
            l2.Add(study2);
            l2.Add(study4);

            Academy a1 = new InsertAcademy()
                 .WithName("AII")
                 .WithStudies(l1);
            Academy a2 = new InsertAcademy()
                 .WithName("WBTK")
                 .WithStudies(l2);
        }

		private void SetupFactory()
		{
			ObjectFactory.Initialize(registry =>
			{
                registry
                     .ForRequestedType<IRepository<Academy>>()
                     .TheDefaultIsConcreteType<BaseRepository<Academy>>();

				registry
					 .ForRequestedType<IRepository<Account>>()
					 .TheDefaultIsConcreteType<AccountRepository>();

				registry
					 .ForRequestedType<IRepository<Person>>()
					 .TheDefaultIsConcreteType<PersonRepository>();

				registry
					.ForRequestedType<IAccountRepository>()
					.TheDefaultIsConcreteType<AccountRepository>();

				registry
					.ForRequestedType<IPersonRepository>()
					.TheDefaultIsConcreteType<PersonRepository>();

				registry
					.ForRequestedType<IRepository<Rooster>>()
					.TheDefaultIsConcreteType<BaseRepository<Rooster>>();

				registry
					.ForRequestedType<IRepository<TimeBlock>>()
					.TheDefaultIsConcreteType<BaseRepository<TimeBlock>>();

				registry
					.ForRequestedType<IRepository<Location>>()
					.TheDefaultIsConcreteType<BaseRepository<Location>>();

				registry
					.ForRequestedType<IRepository<Event>>()
					.TheDefaultIsConcreteType<BaseRepository<Event>>();

				registry
					 .ForRequestedType<IRepository<Registration>>()
					 .TheDefaultIsConcreteType<BaseRepository<Registration>>();

				registry
					 .ForRequestedType<IRepository<EventDate>>()
					 .TheDefaultIsConcreteType<BaseRepository<EventDate>>();

				registry
					 .ForRequestedType<IRepository<Entity>>()
					 .TheDefaultIsConcreteType<BaseRepository<Entity>>();

				registry
					 .ForRequestedType<IRepository<Student>>()
					 .TheDefaultIsConcreteType<BaseRepository<Student>>();

                registry
                     .ForRequestedType<IRepository<Study>>()
                     .TheDefaultIsConcreteType<BaseRepository<Study>>();

				registry
					 .ForRequestedType<IEventRepository>()
					 .TheDefaultIsConcreteType<EventRepository>();

				registry
					.ForRequestedType<IGroupRepository>()
					.TheDefaultIsConcreteType<GroupRepository>();

			});
		}

	}
}
